package com.xbongbong.saas.toolbox.help;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.PropertyFilter;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.serializer.SimplePropertyPreFilter;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.Arith;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.StringConstant;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * fastJson帮助类
 * @author kaka
 */
public class FastJsonHelper {
	
	/**
	 * 解析并返回传过来字段对应的json格式数据
	 * @param clazz  类型实体   UserEntity.class
	 * @param str    需要解析并返回的字段   str = {"id", "userId", "corpid","name"}
	 * @param object 查找数据库后返回内容（可以是单个实体或者集合类型）  UserEntity , UserList
	 * @return
	 */
	public static Object parseIncludeObject(Class<?> clazz,String[] str,Object object){
		SimplePropertyPreFilter filter = new SimplePropertyPreFilter(clazz,str);

		if(object instanceof Collection<?>){
			return JSON.parseArray(JSON.toJSONString(object,filter));
		}else{
			return JSON.parseObject(JSON.toJSONString(object,filter));
		}
	}
	
	/**
	 * 解析并返回排除传过来字段的其他字段对应的json格式数据
	 * @param fields   fields = {"id", "userId", "corpid","name"}
	 * @param object   查找数据库后返回内容（可以是单个实体或者集合类型） UserEntity , UserList
	 * @return 返回过滤对应字段后输出的String
	 */
	public static String parseExcludeObject(final String[] fields, Object object){
		final List<String> list = Arrays.asList(fields);
		return parseExcludeObject(list, object);
	}
	
	/**
	 * 解析并返回排除传过来字段的其他字段对应的json格式数据
	 * @param fields   fields = {"id", "userId", "corpid","name"}
	 * @param object   查找数据库后返回内容（可以是单个实体或者集合类型） UserEntity , UserList
	 * @return 返回过滤对应字段后输出的String
	 */
	public static String parseExcludeObject(final List<String> fields, Object object){
		
        PropertyFilter filter = new PropertyFilter() {
	        //过滤不需要的字段
	        @Override
			public boolean apply(Object source, String name, Object value) {
        	   if(fields.contains(name)){
	                return false;
	           }
        	        return true;
	        }
		};
		return JSON.toJSONString(object, filter, SerializerFeature.DisableCircularReferenceDetect);
	}
	
	
	/**
	 * 解析指定字符串为JSONArray
	 * @param str
	 * @return JSONArray（不为null）
	 * @since 3.13
	 * @version 3.13
	 * @author zheng.li
	 * @time 2017-12-4 上午11:20:26 
	 * @updateTime 2017-12-4 上午11:20:26
	 */
    public static JSONArray  parseArray(String str){
    	JSONArray resultArray = null;
		try{
			resultArray = JSONArray.parseArray(str);
		}catch(Exception e){
			
		}
		if(resultArray==null){
			resultArray = new JSONArray();
		}
    	return resultArray;
    }
    
	/**
	 * 解析指定字符串为JSONObject
	 * @param str
	 * @return JSONObject（不为null）
	 * @since 3.13
	 * @version 3.13
	 * @author zheng.li
	 * @time 2017-12-4 上午11:20:26 
	 * @updateTime 2017-12-4 上午11:20:26
	 */
    public static JSONObject  parseObject(String str){
    	JSONObject resultObject = null;
		try{
			resultObject = JSONArray.parseObject(str);
		}catch(Exception e){
			
		}
		if(resultObject==null){
			resultObject = new JSONObject();
		}
    	return resultObject;
    }

    /**
     * Description: 获取jsonObject的深度，只算第一层（目前导出用）
     * @param jsonObject
     * @return int
     * @author 魏荣杰
     * @date 2019/12/2 2:29 下午
     * @since v4.6.1
     */
    public static int getDepthJsonObjectForExport(JSONObject jsonObject) {
    	int depth = 0;
    	if (jsonObject == null || jsonObject.isEmpty()) {
    		return depth;
		} else {
    		depth = 1;
		}
		Iterator<String> iterator = jsonObject.keySet().iterator();
    	while (iterator.hasNext()) {
			String key = iterator.next();
			Object valueObj = jsonObject.get(key);
			if (valueObj instanceof JSONArray) {
				JSONArray jsonArray = (JSONArray) valueObj;
				if (jsonArray.size() > depth) {
					depth = jsonArray.size();
				}
			}
		}
    	return depth;
	}

	/**
	 * 获取JSONObject类型的数据
	 * 返回可能为null，获取之后需要进行非null判断
	 *
	 * @param data 表单数据
	 * @param attr 要获取数据的key值
	 * @throws XbbException 类型转换失败异常
	 * @author chaoxiong.lei
	 * @Date 14:09 2019/1/23
	 * @since v1.0
	 **/
	public static JSONObject getJsonObjectOrDefaultFromFormData(JSONObject data, String attr, JSONObject defalutValue) throws XbbException {
		JSONObject result = getJsonObjectFromFormData(data, attr);
		if (result == null) {
			return defalutValue;
		}
		return result;
	}

	/**
	 * 获取JSONObject类型的数据
	 * 返回可能为null，获取之后需要进行非null判断
	 *
	 * @param data 表单数据
	 * @param attr 要获取数据的key值
	 * @throws XbbException 类型转换失败异常
	 * @author chaoxiong.lei
	 * @Date 14:09 2019/1/23
	 * @since v1.0
	 **/
	public static JSONObject getJsonObjectFromFormData(JSONObject data, String attr) throws XbbException {
		JSONObject result = null;
		if (data == null || attr == null) {
			return result;
		}
		try {
			return data.getJSONObject(attr);
		} catch (Exception e) {
			return null;
		}
	}

	/**
	 * 获取JSONObject类型的数据，类型错误赋默认值，排错的时候注意下
	 * @param data 数据
	 * @param attr 要获取数据的key值
	 * @param defaultValue 默认值
	 * @return java.lang.JSONObject
	 * @author xinpeng.jiang
	 * @date 2021/11/2 20:04
	 * @version 1.0
	 */
	public static JSONObject getJsonObjectOrDefault(JSONObject data, String attr, JSONObject defaultValue) {
		if (data == null || attr == null) {
			return defaultValue;
		}
		try {
			JSONObject value = data.getJSONObject(attr);
			if (value == null) {
				return defaultValue;
			}
			return value;
		} catch (Exception e) {
			return defaultValue;
		}
	}

	/**
	 * 获取JSONArray类型的数据
	 * 返回可能为null，获取之后需要进行非null判断
	 *
	 * @param data 表单数据
	 * @param attr 要获取数据的key值
	 * @throws XbbException 类型转换失败异常
	 * @author chaoxiong.lei
	 * @Date 14:09 2019/1/23
	 * @update 2019-5-12 by zcp 从SaasUpdateHelp移入
	 * @since v1.0
	 **/
	public static JSONArray getJsonArrOrDefaultFromFormData(JSONObject data, String attr, JSONArray defalutValue) throws XbbException {
		JSONArray jsonArrFromFormData = getJsonArrFromFormData(data, attr);
		if (jsonArrFromFormData == null) {
			jsonArrFromFormData = defalutValue;
		}
		return jsonArrFromFormData;
	}

	/**
	 * 获取JSONArray类型的数据
	 * 返回可能为null，获取之后需要进行非null判断
	 *
	 * @param data 表单数据
	 * @param attr 要获取数据的key值
	 * @throws XbbException 类型转换失败异常
	 * @author chaoxiong.lei
	 * @Date 14:09 2019/1/23
	 * @update 2019-5-12 by zcp 从SaasUpdateHelp移入
	 * @since v1.0
	 **/
	public static JSONArray getJsonArrFromFormData(JSONObject data, String attr) throws XbbException {
		if (data == null || attr == null) {
			return null;
		}
		try {
			if (data.get(attr) == null) {
				return new JSONArray();
			}
			return data.getJSONArray(attr);
		} catch (Exception e) {
			throw new XbbException(SystemErrorCodeEnum.API_ERROR_100015);
		}
	}

	/**
	 * 获取JSONArray类型的数据，类型错误赋默认值，排错的时候注意下
	 * @param data 数据
	 * @param attr 要获取数据的key值
	 * @param defaultValue 默认值
	 * @return java.lang.JSONArray
	 * @author xinpeng.jiang
	 * @date 2021/11/2 20:04
	 * @version 1.0
	 */
	public static JSONArray getJsonArrayOrDefault(JSONObject data, String attr, JSONArray defaultValue) {
		if (data == null || attr == null) {
			return defaultValue;
		}
		try {
			JSONArray value = data.getJSONArray(attr);
			if (value == null) {
				return defaultValue;
			}
			return value;
		} catch (Exception e) {
			return defaultValue;
		}
	}

	/**
	 * 获取Integer类型的数据
	 * 返回可能为null，获取之后需要进行非null判断
	 *
	 * @param data 表单数据
	 * @param attr 要获取数据的key值
	 * @throws XbbException 类型转换失败异常
	 * @author chaoxiong.lei
	 * @Date 14:09 2019/1/23
	 * @since v1.0
	 **/
	public static Integer getIntegerFromFormData(JSONObject data, String attr) throws XbbException {
		if (data == null || attr == null) {
			return null;
		}
		try {
			if (data.get(attr) == null) {
				return null;
			}
			return data.getInteger(attr);
		} catch (Exception e) {
			throw new XbbException(SystemErrorCodeEnum.API_ERROR_100015);
		}
	}


	/**
	 * 获取Integer类型的数据
	 * 返回可能为null，获取之后需要进行非null判断
	 *
	 * @param data 表单数据
	 * @param attr 要获取数据的key值
	 * @throws XbbException 类型转换失败异常
	 * @author chaoxiong.lei
	 * @Date 14:09 2019/1/23
	 * @since v1.0
	 **/
	public static Integer getIntegerOrDefaultFromFormData(JSONObject data, String attr, Integer defaultValue) throws XbbException {
		Integer integerFromFormData = getIntegerFromFormData(data, attr);
		if (Objects.isNull(integerFromFormData)) {
			integerFromFormData = defaultValue;
		}
		return integerFromFormData;
	}

	/**
	 * 获取Integer类型的数据，类型错误赋默认值，排错的时候注意下
	 * @param data 数据
	 * @param attr 要获取数据的key值
	 * @param defaultValue 默认值
	 * @return java.lang.Integer
	 * @author xinpeng.jiang
	 * @date 2021/11/2 20:04
	 * @version 1.0
	 */
	public static Integer getIntegerOrDefault(JSONObject data, String attr, Integer defaultValue) {
		if (data == null || attr == null) {
			return defaultValue;
		}
		try {
			Integer value = data.getInteger(attr);
			if (value == null) {
				return defaultValue;
			}
			return value;
		} catch (Exception e) {
			return defaultValue;
		}
	}

	/**
	 * 获取Double类型的数据
	 * 返回可能为null，获取之后需要进行非null判断
	 *
	 * @param data 表单数据
	 * @param attr 要获取数据的key值
	 * @throws XbbException 类型转换失败异常
	 * @author chaoxiong.lei
	 * @Date 14:09 2019/1/23
	 * @since v1.0
	 **/
	public static Double getDoubleFromFormData(JSONObject data, String attr) throws XbbException {
		Double result = null;
		if (data == null || attr == null) {
			return result;
		}
		try {
			if (data.get(attr) == null) {
				return null;
			}
			return data.getDouble(attr);
		} catch (Exception e) {
			throw new XbbException(SystemErrorCodeEnum.API_ERROR_100015);
		}
	}

	/**
	 * 获取Double类型的数据
	 *
	 * @param data 表单数据
	 * @param attr 要获取数据的key值
	 * @throws XbbException 类型转换失败异常
	 * @author feng.zheng
	 * @Date 14:09 2019/1/23
	 * @since v1.0
	 **/
	public static Double getDoubleOrDefaultFromFormData(JSONObject data, String attr, Double defaultValue) throws XbbException {
		Double doubleFromFormData = getDoubleFromFormData(data, attr);
		if (Objects.isNull(doubleFromFormData)) {
			doubleFromFormData = defaultValue;
		}
		return doubleFromFormData;
	}
	
	/**
	 * 获取Double类型的数据，类型错误赋默认值，排错的时候注意下
	 * @param data 数据
	 * @param attr 要获取数据的key值
	 * @param defaultValue 默认值
	 * @return java.lang.Double
	 * @author xinpeng.jiang
	 * @date 2021/11/2 20:04
	 * @version 1.0
	 */
	public static Double getDoubleOrDefault(JSONObject data, String attr, Double defaultValue) {
		if (data == null || attr == null) {
			return defaultValue;
		}
		try {
			Double value = data.getDouble(attr);
			if (value == null) {
				return defaultValue;
			}
			return value;
		} catch (Exception e) {
			return defaultValue;
		}
	}
	

	/**
	 * 获取String类型的数据
	 * 返回可能为null，获取之后需要进行非null判断
	 *
	 * @param data 表单数据
	 * @param attr 要获取数据的key值
	 * @throws XbbException 类型转换失败异常
	 * @author chaoxiong.lei
	 * @date 14:09 2019/1/23
	 * @since v1.0
	 **/
	public static String getStringFromFormData(JSONObject data, String attr) throws XbbException {
		String result = null;
		if (data == null || attr == null) {
			return result;
		}
		try {
			if (data.get(attr) == null) {
				return null;
			}
			return data.getString(attr);
		} catch (Exception e) {
			throw new XbbException(SystemErrorCodeEnum.API_ERROR_100015);
		}
	}

	/**
	 * 获取String类型的数据
	 *
	 * @param data 表单数据
	 * @param attr 要获取数据的key值
	 * @throws XbbException 类型转换失败异常
	 * @author chaoxiong.lei
	 * @date 14:09 2019/1/23
	 * @since v1.0
	 **/
	public static String getStringOrDefaultFromFormData(JSONObject data, String attr, String defaultValue) throws XbbException {
		String stringFromFormData = getStringFromFormData(data, attr);
		if (Objects.isNull(stringFromFormData)) {
			stringFromFormData = defaultValue;
		}
		return stringFromFormData;
	}

	/**
	 * 获取String类型的数据，类型错误赋默认值，排错的时候注意下
	 * @param data 数据
	 * @param attr 要获取数据的key值
	 * @param defaultValue 默认值
	 * @return java.lang.String
	 * @author xinpeng.jiang
	 * @date 2021/11/2 20:04
	 * @version 1.0
	 */
	public static String getStringOrDefault(JSONObject data, String attr, String defaultValue) {
		if (data == null || attr == null) {
			return defaultValue;
		}
		try {
			String value = data.getString(attr);
			if (value == null) {
				return defaultValue;
			}
			return value;
		} catch (Exception e) {
			return defaultValue;
		}
	}

	/**
	 * 获取Long类型的数据
	 *
	 * @param data 表单数据
	 * @param attr 要获取数据的key值
	 * @throws XbbException 类型转换失败异常
	 * @author feng.zheng
	 * @Date 19:19 2019/1/23
	 * @since v1.0
	 **/
	public static Long getLongFromFormData(JSONObject data, String attr) throws XbbException {
		if (data == null || attr == null) {
			throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028);
		}
		try {
			if (data.get(attr) == null) {
				return null;
			}
			return data.getLong(attr);
		} catch (Exception e) {
			return null;
		}
	}

	/**
	 * 获取Long类型的数据,默认值
	 *
	 * @param data 表单数据
	 * @param attr 要获取数据的key值
	 * @throws XbbException 类型转换失败异常
	 * @author feng.zheng
	 * @Date 19:19 2019/1/23
	 * @since v1.0
	 **/
	public static Long getLongOrDefaultFromFormData(JSONObject data, String attr, Long defaultValue) throws XbbException {
		Long longFromFormData = getLongFromFormData(data, attr);
		if (longFromFormData == null) {
			longFromFormData = defaultValue;
		}
		return longFromFormData;
	}


	/**
	 * 获取Long类型的数据，类型错误赋默认值，排错的时候注意下
	 * @param data 数据
	 * @param attr 要获取数据的key值
	 * @param defaultValue 默认值
	 * @return java.lang.Long
	 * @author xinpeng.jiang
	 * @date 2021/11/2 20:04
	 * @version 1.0
	 */
	public static Long getLongOrDefault(JSONObject data, String attr, Long defaultValue) {
		if (data == null || attr == null) {
			return defaultValue;
		}
		try {
			Long value = data.getLong(attr);
			if (value == null) {
				return defaultValue;
			}
			return value;
		} catch (Exception e) {
			return defaultValue;
		}
	}

	/**
	 * 获取电话集合
	 * 返回可能为null，获取之后需要进行非null判断
	 *
	 * @param data 表单数据
	 * @param attr 要获取数据的key值
	 * @throws XbbException 类型转换失败异常
	 * @author feng.zheng
	 * @date 14:09 2019/2/23
	 * @since v1.0
	 **/
	public static List<String> getPhoneListFromFormData(JSONObject data, String attr) throws XbbException {
		List<String> phoneList = new ArrayList<>();
		if (data == null || attr == null) {
			return phoneList;
		}
		try {
			if (data.get(attr) == null) {
				return phoneList;
			}
			JSONArray phoneArray = data.getJSONArray(attr);
			for (Object obj : phoneArray) {
				JSONObject phoneJsonObject = (JSONObject) obj;
				String tel = phoneJsonObject.getString(StringConstant.PHONE_TEL_ATTR);
				phoneList.add(tel);
			}
		} catch (Exception e) {
			throw new XbbException(SystemErrorCodeEnum.API_ERROR_100015);
		}
		return phoneList;
	}

	/**
	 * 获取Long类型的数据,否则就是默认值，不抛错
	 *
	 * @param data 表单数据
	 * @param attr 要获取数据的key值
	 * @param defaultValue 默认值
	 * @author long.rao
	 * @date 2019-10-17 15:25
	 **/
	public static Long eitherLongOrTheDefault(JSONObject data, String attr, Long defaultValue){
		if (data == null || attr == null) {
			return defaultValue;
		}
		try {
			if (data.get(attr) == null) {
				return defaultValue;
			}
			return data.getLong(attr);
		} catch (Exception e) {
			return defaultValue;
		}
	}

	/**
	 * 处理字段完成率，如现金毛利率、收款比例等
	 * @param updateData 要更新的合同data
	 * @param numerator 分子
	 * @param denominator 分母
	 * @param attr 字段
	 * @author zcp
	 * @date 19/12/6 006 22:28
	 * @since v1.0
	 * @version v1.0
	 * @update 20/2/28 by zcp 从ContractServiceImpl移入
	 */
	public static void handleAttrPercent(JSONObject updateData, Double numerator, Double denominator, String attr) {
		if (Double.compare(denominator, BasicConstant.ZERO) == BasicConstant.ZERO) {
			updateData.put(attr, BasicConstant.ZERO);
		} else {
			updateData.put(attr, Arith.round(Arith.div(numerator, denominator), 4));
		}
	}


	/**
	 * 得到amountDetail，目前只有回款单和发票有该金额明细
	 * @param dataList 前端请求数据dataList
	 * @throws XbbException
	 * @author 伟强
	 * @date 19/11/15 020 14:47
	 * @update 19/11/20 020 14:47 by zcp 兼容发票的amountDetail处理
	 * @since v1.0
	 * @version v1.0
	 */
	public static JSONArray getAmountDetail(JSONObject dataList) throws XbbException {
		//回款单、发票有amountDetail需要处理
		if(Objects.nonNull(dataList)) {
			if (dataList.containsKey(PaasConstant.AMOUNTDETAIL)) {
				//回款单中金额明细
				JSONArray amountDetail = FastJsonHelper.getJsonArrOrDefaultFromFormData(dataList, PaasConstant.AMOUNTDETAIL, new JSONArray());
				return amountDetail;
			}
		}
		return null;
	}


	/**
	 * 根据字段类型获取穿透后字段的value值
	 *
	 * @param obj Integer、String、JsonObject
	 * @return java.lang.String
	 * @author zyy
	 * @date 2022/6/6
	 * @version v1.0
	 */
	public static String getAttrValueByType(Object obj) {
		try {
			if(Objects.isNull(obj)){
				return "";
			}
			if(obj instanceof JSONObject){
				JSONObject jsonObject = (JSONObject) obj;
				return jsonObject.getString("value");
			}
			return obj + "";
		}catch (Exception e){
			return "";
		}
	}

	/**
	 * 获取指定的类型集合数据
	 * @param data
	 * @param attr
	 * @param transferType
	 * @param <T>
	 * @return
	 */
	public static  <T> List<T> getTransferTypesFromData(JSONObject data, String attr, Class<T> transferType) {
		List<T> ids = Collections.emptyList();
		if (Objects.isNull(data) || Objects.isNull(attr)) {
			return ids;
		}

		JSONArray jsonArray;
		try {
			 jsonArray = data.getJSONArray(attr);
			if (Objects.nonNull(jsonArray) && !jsonArray.isEmpty()) {
				return jsonArray.toJavaList(transferType);
			}
		} catch (Exception e) {
			try {
				// 可能为不合法的array类型
				Object obj = data.get(attr);
				List<Object> objects = Arrays.asList(obj);
				jsonArray = (JSONArray) JSON.toJSON(objects);
				if (Objects.nonNull(jsonArray) && !jsonArray.isEmpty()) {
					return jsonArray.toJavaList(transferType);
				}
			} catch (Exception exception) {
				return ids;
			}
		}

		return ids;
	}

	/**
	 * 只处理自定义目标字段类型为单选、复选、下拉框、下拉复选字段穿透的值的渲染
	 *
	 * @param object 待处理的对象
	 * @return 处理完的value
	 */
	public static String getValueByFieldType(Object object) {
		try {
			if (Objects.isNull(object)) {
				return "";
			}
			if (object instanceof JSONObject) {
				JSONObject jsonObject = (JSONObject) object;
				return jsonObject.getString("text");
			} else if (object instanceof JSONArray) {
				JSONArray jsonArray = (JSONArray) object;
				List<String> valueString = jsonArray.stream().map(json -> {
					if (json instanceof JSONObject) {
						JSONObject jsonObject = (JSONObject) json;
						return jsonObject.getString("text");
					}
					return json.toString();
				}).collect(Collectors.toList());
				return StringUtils.join(valueString, "、");
			}
			return object.toString();
		} catch (Exception e) {
			return "";
		}
	}

}
